package com.example.user.filter;

import brave.Span;
import brave.Tracer;
import org.springframework.cloud.sleuth.instrument.web.SleuthWebProperties;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.regex.Pattern;

/**
 * @Author 刘武贵
 * @Date 2024-03-10 12:40
 * @Description 功能描述：链路过滤器
 * 本案例演示通过过滤器验证只有HTTP或者HTTPS请求才能访问接口，并且在访问的链接不是静态文件时，
 * 将traceId放入HttpRequest中在服务端获取，并在响应结果中添加自定义Header，名称为SLEUTH-HEADER，值为traceId。
 */
/**
 * MyGenericFilter类继承自GenericFilterBean，用于实现自定义的过滤逻辑。
 * 通过@Component注解将其注册为一个Spring组件，@Order注解指定了其执行顺序。
 */
@Component
@Order( Ordered.HIGHEST_PRECEDENCE + 6)
public class MyGenericFilter extends GenericFilterBean {

    /**
     * 定义跳过跟踪的URL模式
     */
    private Pattern skipPattern = Pattern.compile(SleuthWebProperties.DEFAULT_SKIP_PATTERN);

    /**
     * Tracer对象用于进行跟踪
     */
    private final Tracer tracer;

    /**
     * 构造函数，注入Tracer对象
     */
    public MyGenericFilter(Tracer tracer){
        this.tracer = tracer;
    }

    /**
     * 过滤器的核心方法，用于处理请求并进行链式调用。
     *
     * @param request Servlet请求对象
     * @param response Servlet响应对象
     * @param chain 过滤器链，用于执行下一个过滤器或处理程序
     * @throws IOException 如果发生输入/输出错误
     * @throws ServletException 如果发生与Servlet相关的异常
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {

        // 检查请求和响应是否为HTTP类型
        if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)){
            throw new ServletException("只支持HTTP访问");
        }

        // 获取当前的跟踪Span
        Span currentSpan = this.tracer.currentSpan();
        // 如果当前没有跟踪Span，则直接通过过滤器链
        if (currentSpan == null) {
            chain.doFilter(request, response);
            return;
        }

        // 针对HTTP请求进行处理
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = ((HttpServletResponse) response);

        // 判断当前请求是否应该被跳过跟踪
        boolean skipFlag = skipPattern.matcher(httpServletRequest.getRequestURI()).matches();
        // 如果不跳过，则添加Trace ID到请求和响应中
        if (!skipFlag){
            String traceId = currentSpan.context().traceIdString();
            httpServletRequest.setAttribute("traceId", traceId);
            httpServletResponse.addHeader("SLEUTH-HEADER", traceId);
        }
        // 继续传递请求到下一个过滤器或处理程序
        chain.doFilter(httpServletRequest, httpServletResponse);
    }
}